//
//  YMSystemAuthManager.swift
//  ViomiSystemAuth
//
//  Created by 陈狄夫 on 2021/5/12.
//

import Foundation
import UIKit
import Photos
import Intents
import UserNotifications
import Contacts
import CoreLocation
import AppTrackingTransparency
import CoreBluetooth
import VMUIKit


@objc public enum YMSystemAuthType :Int {
    case photoLibraryAuth // 相册浏览 图片写入
    case cameraAuth // 相机
    case microphoneAuth // 麦克风
    case siriAuth // siri
    case pushAuth // 推送
    case addressBookAuth // 通讯录
    case locationAuth // 定位
    case adFlagAuth // 广告标识
    case bluetoothAuth // 蓝牙
    case wifiAuth // wifi
    case miHomeAuth // 米家
}

@objc public enum YMSystemAuthStatus : Int {
    case limited  = 0 // 无权限 包括Restricted 、Denied
    case notDetrtmined = 1 // 未询问
    case noLimited = 2 // 有权限
}

public typealias getAuthStatus = (YMSystemAuthType,YMSystemAuthStatus) -> Void
//public typealias popupView = () -> (UIView)
public typealias requestCancel = () -> ()
public typealias requestSubmit = () -> ()
public typealias locationBlock = (Bool) -> ()


@objc public class YMSystemAuthManager : NSObject, CLLocationManagerDelegate {
    
    //创建一个静态或者全局变量，保存当前单例实例值
    private static let manager = YMSystemAuthManager()
    private let locationManager = CLLocationManager.init()
    var block : locationBlock? = nil
    
    
    // 私有化构造方法
    private override init() {
        super.init()
        locationManager.delegate = self
    }
    
    
    //提供一个公开的用来去获取单例的方法
    @objc public class func defaultManager() -> YMSystemAuthManager {
        return manager
    }
    
    @objc public func checkAuthStatus(auth : YMSystemAuthType , getAuthStatus : @escaping getAuthStatus)  {
        switch auth {
        case .photoLibraryAuth:getAuthStatus(auth,checkPhotoLibraryAuth())
        case .cameraAuth:getAuthStatus(auth,checkCameraAuth())
        case .microphoneAuth:getAuthStatus(auth,checkPhotoLibraryAuth())
        case .siriAuth:getAuthStatus(auth,checkSiriAuth())
        case .pushAuth:checkPushAuth(getAuthStatus: getAuthStatus)
        case .addressBookAuth:getAuthStatus(auth,checkAddressBookAuth())
        case .locationAuth:getAuthStatus(auth,checkLocationAuth())
        case .adFlagAuth:checkADAuth(getAuthStatus: getAuthStatus)
        case .bluetoothAuth:getAuthStatus(auth,checkBluetoothAuth())
        case .wifiAuth:getAuthStatus(auth,checkWiFiAuth())
        case .miHomeAuth:getAuthStatus(auth,checkMiHomeAuth())
            
        }
    }
    
    // 相册权限
    func checkPhotoLibraryAuth() -> YMSystemAuthStatus {
        let status = PHPhotoLibrary.authorizationStatus()
        if (status == .denied || status == .restricted) {
            return .limited
        }else if status == .notDetermined {
            return .notDetrtmined
        }else{
            return.noLimited
        }
    }
    
    // 相机权限
    func checkCameraAuth() -> YMSystemAuthStatus {
        let status = AVCaptureDevice.authorizationStatus(for: AVMediaType.video)
        if status == .denied || status == .restricted {
            return .limited
        }else if status == .notDetermined {
            return .notDetrtmined
        }else{
            return .noLimited
        }
    }

    // 麦克风权限
    func checkMicrophoneAuth() -> YMSystemAuthStatus {
        let status = AVCaptureDevice.authorizationStatus(for: AVMediaType.audio)
        if status == .denied || status == .restricted {
            return .limited
        }else if status == .notDetermined {
            return .notDetrtmined
        }else{
            return .noLimited
        }
    }
    
    // Siri权限
    func checkSiriAuth() -> YMSystemAuthStatus {
        let status = INPreferences.siriAuthorizationStatus()
        if status == .denied || status == .restricted {
            return .limited
        }else if status == .notDetermined {
            return .notDetrtmined
        }else{
            return .noLimited
        }
    }
    
    // 推送权限
    func checkPushAuth(getAuthStatus : @escaping getAuthStatus)   {
        
        UNUserNotificationCenter.current().getNotificationSettings(){ (setttings) in
            switch setttings.authorizationStatus{
            case .authorized:
                getAuthStatus(.pushAuth,.noLimited)
            case .notDetermined:
                getAuthStatus(.pushAuth,.notDetrtmined)
            case .denied:
                fallthrough
             default:
                getAuthStatus(.pushAuth,.limited)
            }
        }
    }
    
    // 通讯录权限
    func checkAddressBookAuth() -> YMSystemAuthStatus {
        let status = CNContactStore.authorizationStatus(for: CNEntityType.contacts)
        if status == .denied || status == .restricted {
            return .limited
        }else if status == .notDetermined {
            return .notDetrtmined
        }else{
            return .noLimited
        }
    }
    
    // 定位权限
    func checkLocationAuth() -> YMSystemAuthStatus {
        let status = CLLocationManager.authorizationStatus()
        if status == .denied || status == .restricted {
            return .limited
        }else if status == .notDetermined {
            return .notDetrtmined
        }else{
            return .noLimited
        }
    }
    
    // 广告标识权限
    func checkADAuth(getAuthStatus :@escaping getAuthStatus)  {
        guard #available(iOS  14.0 , *) else {
            getAuthStatus(.adFlagAuth,.limited)
            return
        }
        
        ATTrackingManager.requestTrackingAuthorization { (status : ATTrackingManager.AuthorizationStatus) in
            switch status {
            case .authorized:
                getAuthStatus(.adFlagAuth,.noLimited)
            case .notDetermined:
                getAuthStatus(.adFlagAuth,.notDetrtmined)
            case .denied:
                fallthrough
            case .restricted:
                fallthrough
            @unknown default:
                getAuthStatus(.adFlagAuth,.limited)
            }
        }
    }
    
    // 蓝牙状态
    func checkBluetoothAuth() -> YMSystemAuthStatus {
        let manager = CBCentralManager()
        if manager.state == .poweredOn {
            return .noLimited
        }else{
            return .limited
        }
        
    }
    
    // wifi连接状态
    func checkWiFiAuth() -> YMSystemAuthStatus {
        let ssid : String? = YMWiFiTools.getCurrentWiFiSsid()
        if ssid != nil {
            return .noLimited
        }else{
            return .limited
        }
        
    }
    
    // 米家权限
    func checkMiHomeAuth() -> YMSystemAuthStatus {
        let  userDefaults = UserDefaults.standard
        let miID : String? = userDefaults.string(forKey: "viomi_miuser_mid_key")
        if miID != nil {
            return .noLimited
        }
        return .limited
    }
    
    
    @objc public func requestAuth(auth : YMSystemAuthType , getAuthStatus :@escaping getAuthStatus, showPopupView : Bool , requestCancel : requestCancel? = nil , requestSubmit : requestSubmit? = nil) {
        if showPopupView {
            DispatchQueue.main.async {
                let popupView = YMSystemAuthPopupView.init(config: VMUIBasePopupViewConfig.default())
                popupView.submitClicked = {
                    if let submit = requestSubmit {
                        submit()
                    }
                    self.requestAuth(auth: auth, getAuthStatus: getAuthStatus)
                }
                popupView.cancelClicked = {
                    if let cancel = requestCancel {
                        cancel()
                    }
                }
                
                popupView.show(nil)
            }
        }else{
            requestAuth(auth: auth, getAuthStatus: getAuthStatus)
        }
        
    }
    
    func requestAuth(auth : YMSystemAuthType , getAuthStatus : @escaping getAuthStatus) {
        switch auth {
        case .photoLibraryAuth:requestPhotoLibraryAuth(getAuthStatus: getAuthStatus)
        case .cameraAuth:requestCameraAuth(getAuthStatus: getAuthStatus)
        case .microphoneAuth:requestMicrophoneAuth(getAuthStatus: getAuthStatus)
        case .siriAuth:requestSiriAuth(getAuthStatus: getAuthStatus)
        case .pushAuth:requestPushAuth(getAuthStatus: getAuthStatus)
        case .addressBookAuth:requestAddressBookAuth(getAuthStatus: getAuthStatus)
        case .locationAuth:requestLocationAuth(getAuthStatus: getAuthStatus)
        case .adFlagAuth:requestADFlagAuth(getAuthStatus: getAuthStatus)
            // 后面3个自己处理
        case .bluetoothAuth:getAuthStatus(.bluetoothAuth,.notDetrtmined)
        case .wifiAuth:getAuthStatus(.bluetoothAuth,.notDetrtmined)
        case .miHomeAuth:getAuthStatus(.bluetoothAuth,.notDetrtmined)
        }
    }
    
    func requestPhotoLibraryAuth(getAuthStatus : @escaping getAuthStatus) {
        PHPhotoLibrary.requestAuthorization { (status) in
            switch status {
            case .limited:
                fallthrough
            case .authorized :
                getAuthStatus(.photoLibraryAuth,.noLimited)
            case .notDetermined:
                getAuthStatus(.photoLibraryAuth,.notDetrtmined)
            case .restricted:
                fallthrough
            case .denied:
                fallthrough
            default:
                getAuthStatus(.photoLibraryAuth,.limited)
            }
        }
    }
    
    func requestCameraAuth(getAuthStatus : @escaping getAuthStatus) {
        AVCaptureDevice.requestAccess(for: AVMediaType.video) { (granted) in
            if granted {
                getAuthStatus(.cameraAuth,.noLimited)
            }else{
                getAuthStatus(.cameraAuth,.noLimited)
            }
        }
    }
    
    func requestMicrophoneAuth(getAuthStatus : @escaping getAuthStatus) {
        AVCaptureDevice.requestAccess(for: AVMediaType.audio) { (granted) in
            if granted {
                getAuthStatus(.cameraAuth,.noLimited)
            }else{
                getAuthStatus(.cameraAuth,.limited)
            }
        }
    }
    
    func requestSiriAuth(getAuthStatus : @escaping getAuthStatus) {
        INPreferences.requestSiriAuthorization { (status) in
            switch status {
            case .authorized :
                getAuthStatus(.cameraAuth,.noLimited)
            case .notDetermined:
                getAuthStatus(.cameraAuth,.notDetrtmined)
            case .restricted:
                fallthrough
            case .denied:
                fallthrough
            default:
                getAuthStatus(.cameraAuth,.limited)
            }
        }
    }
    
    func requestPushAuth(getAuthStatus :@escaping getAuthStatus) {
        UNUserNotificationCenter.current().requestAuthorization(options: [.badge,.sound,.alert]) { (granted, error) in
            guard error != nil else{
                getAuthStatus(.pushAuth,.limited)
                return
            }
            if granted {
                getAuthStatus(.pushAuth,.noLimited)
            }else{
                getAuthStatus(.pushAuth,.limited)
            }
        }
    }
    
    func requestAddressBookAuth(getAuthStatus : @escaping getAuthStatus) {
        let contactStore = CNContactStore.init()
        contactStore .requestAccess(for: CNEntityType.contacts) { (granted, error) in
            guard error != nil else {
                getAuthStatus(.addressBookAuth,.limited)
                return
            }
            if granted {
                getAuthStatus(.addressBookAuth,.noLimited)
            }else{
                getAuthStatus(.addressBookAuth,.limited)
            }
        }
    }
    
    func requestLocationAuth(getAuthStatus : @escaping getAuthStatus) {
        self.locationManager.requestWhenInUseAuthorization()
        self.block = { (granted) in
            if granted {
                getAuthStatus(.locationAuth,.noLimited)
            }else{
                getAuthStatus(.locationAuth,.limited)
            }
        }
    }
    
    func requestADFlagAuth(getAuthStatus : @escaping getAuthStatus) {
        if #available(iOS 14, *) {
            ATTrackingManager.requestTrackingAuthorization { (status) in
                switch status {
                case .authorized :
                        getAuthStatus(.adFlagAuth,.noLimited)
                case .notDetermined:
                        getAuthStatus(.adFlagAuth,.notDetrtmined)
                case .restricted:
                        fallthrough
                case .denied:
                    fallthrough
                @unknown default:
                    getAuthStatus(.adFlagAuth,.limited)
                }
            }
        } else {
            // Fallback on earlier versions
                getAuthStatus(.adFlagAuth,.limited)
        }
    }
    
    
    // LocationDelegate
    
    public func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        if self.block != nil {
            self.block!(true)
        }
    }
    
    public func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        if self.block != nil {
            self.block!(false)
        }
    }
}
